package com.baturu.vin.dffx.service.impl;

import com.baturu.carvin.dtos.CarTypeDTO;
import com.baturu.carvin.service.CarTypeService;
import com.baturu.vin.base.service.impl.EPCAnalyser;
import com.baturu.vin.base.util.MD5Utils;
import com.baturu.vin.dffx.dal.dao.*;
import com.baturu.vin.dffx.domain.QueryImageParamDTO;
import com.baturu.vin.dffx.dto.*;
import com.baturu.vin.dto.*;
import com.baturu.vin.service.EPCVinCacheService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service("dffxEPCAnalyser")
public class DffxEPCAnalyser extends EPCAnalyser<DffxVinDTO, DffxPartsMappingDTO, DffxPartsInfoDTO, EPCCarTypeDTO> {
    private final static int OFFSET = 35;
    @Autowired
    DffxVinDAO dffxVinDAO;
    @Autowired
    DffxCarSystemDAO dffxCarSystemDAO;
    @Autowired
    DffxPartsMappingDAO dffxPartsMappingDAO;
    @Autowired
    DffxPartsInfoDAO dffxPartsDAO;
    @Autowired
    DffxPartsImageDAO dffxPartsImageDAO;
    @Autowired
    private EPCVinCacheService epcVinCacheService;
    @Autowired
    private CarTypeService carTypeService;

    @Override
    protected DffxVinDTO analyseVinCode(String vinCode) {
        DffxVinDTO vinModel = dffxVinDAO.findVinModel(vinCode);
        if (Objects.isNull(vinModel)) {
            epcVinCacheService.addWaitCacheVinCode(EPCAnalyserEnum.DFFX, vinCode);
            return null;
        }
        return vinModel;
    }

    @Override
    protected DffxVinDTO analyseVinCodeByCache(String vinCode) {
        return dffxVinDAO.findVinModel(vinCode);
    }

    @Override
    protected List<EPCCarTypeDTO> queryCarTypes(DffxVinDTO analyseResult) {
        DffxCarSystemDTO carSystemBtrIdDTO = buildCarType(analyseResult);
        if (Objects.isNull(carSystemBtrIdDTO)) {
            return Collections.emptyList();
        }
        EPCCarTypeDTO epcCarTypeDTO = new EPCCarTypeDTO();
        epcCarTypeDTO.setBtrId(carSystemBtrIdDTO.getBtrId());
        return Lists.newArrayList(epcCarTypeDTO);
    }

    private DffxCarSystemDTO buildCarType(DffxVinDTO analyseResult) {
        if (Objects.isNull(analyseResult)) {
            return null;
        }
        String btrId = getDffxBtrId(analyseResult);
        DffxCarSystemDTO dffxCarSystemDTO = dffxCarSystemDAO.queryCarSystemIdBycarSystem(analyseResult.getCarSystem());
        dffxCarSystemDTO.setBtrId(btrId);

        saveCarType(analyseResult, dffxCarSystemDTO);
        return dffxCarSystemDTO;
    }

    private int saveCarType(DffxVinDTO analyseResult, DffxCarSystemDTO dffxCarSystemDTO) {
        String btrId = dffxCarSystemDTO.getBtrId();
        if (StringUtils.isBlank(btrId)) {
            return 0;
        }
        List<CarTypeDTO> carTypeDTOs = carTypeService.findCarTypeByBtrIds(Lists.newArrayList(btrId));
        if (CollectionUtils.isNotEmpty(carTypeDTOs)) {
            return 0;
        }

        return epcVinCacheService.saveNewCarType(Lists.newArrayList(CarTypeBuilderDTO
                .builder()
                .btrId(btrId)
                .carSystem(analyseResult.getCarSystem())
                .displacement(analyseResult.getDisplacement())
                .btrBrand(analyseResult.getBtrBrand())
                .btrSubBrand(analyseResult.getBtrSubBrand())
                .transmissionType(analyseResult.getTransmissionType())
                .transmissionDesc(analyseResult.getTransmissionDesc())
                .carSystemId(dffxCarSystemDTO.getCarSystemId())
                .seats(analyseResult.getSeats())
                .btrCountry("中国")
                .productTime(analyseResult.getMj())
                .salesName(analyseResult.getDisplacement() + " " + analyseResult.getCarType())
                .build()));
    }

    private String getDffxBtrId(DffxVinDTO analyseResult) {
        List<DffxCarSystemDTO> dffxCarSystemDTOs = dffxCarSystemDAO.queryBtrIdByCondition(analyseResult);
        if (CollectionUtils.isNotEmpty(dffxCarSystemDTOs)) {
            return dffxCarSystemDTOs.get(0).getBtrId();
        }
        String btrId = "DffxEPC_" + MD5Utils.getMD5Code(analyseResult.getCarSystem() + analyseResult.getDisplacement() + analyseResult.getTransmissionType()) + "_" + analyseResult.getMj();
        DffxCarSystemDTO carSystem = DffxCarSystemDTO.builder()
                .btrId(btrId)
                .carSystem(analyseResult.getCarSystem())
                .displacement(analyseResult.getDisplacement())
                .transmission(analyseResult.getTransmissionType())
                .year(analyseResult.getMj())
                .build();
        dffxCarSystemDAO.insertCarSystemBtrId(carSystem);
        return btrId;
    }


    @Override
    protected List<DffxPartsMappingDTO> queryPartsMappings(Set<String> btrPartsNames, DffxVinDTO analyseResult) {
        return dffxPartsMappingDAO.queryPartsMappingBySeriesAndBtrPartsName( btrPartsNames);
    }

    @Override
    protected List<DffxPartsInfoDTO> queryPartsInfoByPartsMapping(List<DffxPartsMappingDTO> partsMappings, DffxVinDTO analyseResult) {
        Set<String> partsCodeList = partsMappings.stream()
                .map(DffxPartsMappingDTO::getPartsCode)
                .collect(Collectors.toSet());

        return queryPartsInfoByPartsCode(partsCodeList, analyseResult);
    }

    @Override
    protected List<DffxPartsInfoDTO> queryPartsInfoByPartsCode(Set<String> partsCodes) {
        if (CollectionUtils.isEmpty(partsCodes)) {
            return Collections.emptyList();
        }
        return dffxPartsDAO.queryPartsByPartsCode(partsCodes);
    }

    @Override
    protected List<DffxPartsInfoDTO> queryPartsInfoByPartsCode(Set<String> partsCodes, DffxVinDTO analyseResult) {
        return dffxPartsDAO.queryPartsBySeries(analyseResult.getCarSystem(), partsCodes);
    }

    @Override
    protected List<DffxPartsInfoDTO> filterPartsInfoByVinAnalyseResult(List<DffxPartsInfoDTO> partsInfo, DffxVinDTO analyseResult) {
        partsInfo.removeIf(d -> !matchDate(d, analyseResult.getMj()));
        return partsInfo;
    }

    private boolean matchDate(DffxPartsInfoDTO d, String mj) {
        String startDate = StringUtils.substringBefore(d.getStartDate(), "-");
        String endDate = StringUtils.substringBefore(d.getEndDate(), "-");
        return mj.compareTo(startDate) >= 0 && mj.compareTo(endDate) <= 0;
    }

    @Override
    protected Map<String, List<EPCPartsImageDTO>> queryPartsImage(Map<String, List<DffxPartsInfoDTO>> partsInfoGroup, DffxVinDTO analyseResult) {
        Set<QueryImageParamDTO> queryImageParam = partsInfoGroup.values().stream()
                .flatMap(Collection::stream)
                .filter(d -> !StringUtils.equals(d.getOrderIndex(), "0"))
                .map(d -> QueryImageParamDTO.builder()
                        .ordIndex(d.getOrderIndex())
                        .partSructOid(d.getPartStruOid())
                        .build()).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(queryImageParam)) {
            return Collections.emptyMap();
        }
        List<DffxPartsImageDTO> dffxPartsImageDTOs = dffxPartsImageDAO.queryImage(queryImageParam);
        Map<String, List<DffxPartsImageDTO>> imageGroupByCode = dffxPartsImageDTOs.stream().collect(Collectors.groupingBy(DffxPartsImageDTO::getSpareoid));
        //获取图片名字
        Set<String> queryForName = queryImageParam.stream().map(QueryImageParamDTO::getPartSructOid).collect(Collectors.toSet());
        if(CollectionUtils.isEmpty(queryForName)) {
            return Collections.emptyMap();
        }
        Map<String, String> nameGroupBypartStru = dffxPartsImageDAO.queryImageName(queryForName).stream().collect(Collectors.toMap(DffxPartsImageInfoDTO::getPartStructOid,DffxPartsImageInfoDTO::getImageName,(v1,v2) -> v1));
        return partsInfoGroup.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream()
                .flatMap(d -> dffxPartsImageDTOs.stream().filter(i -> StringUtils.equals(d.getOrderIndex(),i.getOrdIndex())).filter(i -> StringUtils.equals(d.getPartStruOid(),i.getPartSructOid())))
                .map(image -> {
                    EPCPartsImageDTO epcPartsImageDTO = new EPCPartsImageDTO();
                    epcPartsImageDTO.setImageUrl(appConfigLoader.getPartsPicBaseUrl() + String.format("dffx/%s", image.getImageUrl()));
                    epcPartsImageDTO.setImageCode(image.getSpareoid());
                    epcPartsImageDTO.setImageName(nameGroupBypartStru.get(image.getPartSructOid()));

                    List<DffxPartsImageDTO> imageDTOs = imageGroupByCode.get(image.getPartSructOid());
                    if(CollectionUtils.isNotEmpty(imageDTOs)) {
                        epcPartsImageDTO.setEpcPartsImagePositionDTOs(buildEPCPartsImagePositionDTO(imageDTOs));
                    }
                    return epcPartsImageDTO;
                }).distinct().collect(Collectors.toList())
        ));
    }

    private List<EPCPartsImagePositionDTO> buildEPCPartsImagePositionDTO(List<DffxPartsImageDTO> imageDTOs) {
        return imageDTOs.stream().map(d -> {
            EPCPartsImagePositionDTO position = new EPCPartsImagePositionDTO();
            position.setPosition(d.getOrdIndex());
            String positionX = StringUtils.isNotBlank(d.getPointX()) ? d.getPointX() : "0";
            String positionY = StringUtils.isNotBlank(d.getPointY()) ? d.getPointY() : "0";

            position.setTopLeft(new EPCImagePointDTO(Integer.parseInt(positionX), Integer.parseInt(positionY)));
            position.setBottomRight(new EPCImagePointDTO(Integer.parseInt(positionX) + OFFSET, Integer.parseInt(positionY) + OFFSET));
            return position;
        }).distinct().collect(Collectors.toList());
    }

    @Override
    protected List<DffxPartsMappingDTO> queryPartsMappingByPartsInfoAndAnalyseResult(Map<String, List<DffxPartsInfoDTO>> partsInfoGroup, DffxVinDTO analyseResult) {
        if (Objects.isNull(analyseResult)) {
            return Collections.emptyList();
        }
        Set<String> partsCodes = partsInfoGroup.values().stream()
                .flatMap(l -> l.stream().map(DffxPartsInfoDTO::getPartsCode))
                .collect(Collectors.toSet());
        return dffxPartsMappingDAO.queryByPartsCode(analyseResult.getCarSystem(), partsCodes);
    }

    @Override
    protected Map<String, String> queryEpcPartsName(Map<String, List<DffxPartsInfoDTO>> partsInfoGroup, DffxVinDTO analyseResult) {
        return partsInfoGroup.values().stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toMap(DffxPartsInfoDTO::getPartsCode, DffxPartsInfoDTO::getEpcName, (v1, v2) -> v1));
    }
}
